# BSD3.0
# cili@163.com

from os import environ

environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1'

import pygame
import os
import json
import hashlib

start=0;goal=0;steps=0
op='等待输入......'
pillars=[]

def calculate_md5(file_path):
    try:
        hash_md5 = hashlib.md5()
        with open(file_path, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                hash_md5.update(chunk)
        return hash_md5.hexdigest()
    except:
        return None


file_md5 = calculate_md5('key.bin')
change_flag,disk_num = (True,6) if file_md5 in ['4a24be5cf48847da2c055a6c43f19d4a'] else (False,3)


current_file_path = os.path.abspath(__file__)
current_directory = os.path.dirname(current_file_path)

class Pillar:
    def __init__(self,no,x,y):
        self.no=no;self.x=x;self.y=y
        self.disks=[]

    def addDisk(self,disk_no):
        result =False
        tmp = -1
        if (len(self.disks) > 0): tmp = self.disks[-1]
        if (tmp > disk_no or tmp == -1):
            self.disks.append(disk_no)
            result=True
        return result

    def topDisk(self):
        return self.disks[-1] if len(self.disks)>0 else -1

    def popDisk(self):
        if len(self.disks)>0:
            self.disks.remove(self.disks[-1])

    def draw(self,surface):
        pygame.draw.line(surface,(0,0,0),(self.x,self.y),(self.x + 200,self.y),2)
        pygame.draw.line(surface,(0, 0, 0),(self.x+100, self.y), (self.x + 100, self.y-130), 2)
        for i,v in enumerate(self.disks):
            w = 200 - (disk_num  - v+1) * 26;
            rx = int(self.x + 100 - w / 2);
            ry = self.y - 20 * (i + 1);
            pygame.draw.rect(screen,(0,255-v*30,0),(rx,ry,w,20),0)
        txt_surface = font.render(str(self.no), True, (0,0, 0)).convert_alpha()
        surface.blit(txt_surface, (self.x+95, self.y+10))

def draw(screen):
    screen.fill((137,207,240))
    screen.blit(font2.render('汉诺塔游戏', True, (0,0, 0)).convert_alpha(), (300, 60));
    for p in pillars:
        p.draw(screen)
    screen.blit(font.render(op, True, (0, 0, 0)).convert_alpha(), (50,570))
    message =['1.把所有圆环从柱1移到柱3。', '2.小圆环必须放到大圆环上。', '3.敲1、2、3可以移动圆环。', '4.敲 r 可以重新游戏。','5.敲上、下方向键可以增加或减少圆环(3~6)。']
    if not change_flag:message = message[0:4]
    for index, txt in enumerate(message):
        screen.blit(font.render(txt, True, (0, 0, 0)).convert_alpha(), (50, 150+30*index))
    screen.blit(font.render('步骤数: %d' % steps, True, (0, 0, 0)).convert_alpha(), (650, 150));
    screen.blit(font.render('圆环数: %d' % disk_num, True, (0, 0, 0)).convert_alpha(), (650, 180));
    if len(pillars[2].disks)==disk_num:
        screen.blit(font2.render('胜利了！！！', True, (255, 0, 0)).convert_alpha(), (240, 330));
    pygame.display.update()

def init(n):
    global  start,goal,steps,op
    pillars.clear();start=0;goal=0;steps=0;op='等待输入......'
    disk_num=n
    for i in [1, 2, 3]: pillars.append(Pillar(i, 50 + 250 * (i - 1),500))
    for i in range(disk_num,0,-1):pillars[0].addDisk(i)
    draw(screen)

def move(s, g):
    global steps,op
    tmp = pillars[s - 1].topDisk()
    pillars[g - 1].addDisk(tmp)
    pillars[s - 1].popDisk()
    steps = steps + 1;
    op='移动圆环：从 %d 到 %d' %(s,g)
    draw(screen)
    pygame.time.wait(500)

def autoMove(n, s, g, t):
    if n == 1:
        move(s, g)
    elif n > 1:
        autoMove(n - 1, s, t, g)
        move(s, g)
        autoMove(n - 1, t, g, s)

pygame.init()
font_path = f"{current_directory}/wqy-microhei.ttc"
font = pygame.font.Font(font_path, 16)
font2 = pygame.font.Font(font_path, 48)
SCREEN_SIZE = (800, 600)
pygame.display.set_caption('汉诺塔游戏')
screen = pygame.display.set_mode(SCREEN_SIZE,0,32)
init(disk_num)


run_flag=True
while run_flag:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run_flag = False

        if event.type==pygame.KEYDOWN:
            
            if event.key==pygame.K_DOWN:
                if not change_flag : continue
                disk_num=disk_num-1 if disk_num>3 else disk_num
                init(disk_num)

            if event.key == pygame.K_UP:
                if not change_flag: continue
                disk_num = disk_num + 1 if disk_num < 6 else disk_num
                init(disk_num)

            if event.key == pygame.K_r:
                init(disk_num)

            if event.key == pygame.K_a:
                init(disk_num)
                autoMove(disk_num,1,3,2)

            if event.key in [pygame.K_1,pygame.K_2,pygame.K_3,1073741913,1073741914,1073741915]:
                v_k=int(event.key)-48 if (int(event.key)<100) else int(event.key)-1073741912
                if (start == v_k):
                    start = 0;goal = 0
                    op = "不能移给自己。"
                    draw(screen)
                    continue

                if start == 0 and start != v_k:
                    if (len(pillars[v_k-1].disks)==0) :
                        op='%d 没有圆环!'% (v_k)
                    else:
                        start = v_k
                        op='移动圆环：从 %d ' % start
                    draw(screen)
                    continue

                if start * goal == 0 and start != v_k:
                    goal=v_k;
                    op = op + '到 %d' % goal
                    tmp=pillars[start-1].topDisk()
                    if tmp > 0:
                        r=pillars[goal - 1].addDisk(tmp);
                        if (r):
                            pillars[start-1].popDisk();
                            steps=steps+1;
                            op=op+' 成功.'
                        else :
                            op=op+' 失败.'
                    start=0;goal=0
                    draw(screen)
pygame.quit()
